package com.tools.web.interceptor.auth;

import com.tools.common.exception.DataGenerationException;
import com.tools.common.exception.InvalidDataException;
import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;

import java.util.Objects;

/**
 * 通用逻辑的 AuthToken 抽象类
 * */
@Note("通用逻辑的 AuthToken 抽象类")
public abstract class GenericAuthToken implements AuthToken {

    @Note("UUID 标识前缀，标识这是某一条登录记录（一般用于存储在缓存中才使用）")
    private String uuid;

    @Note("用户/账户 ID")
    private Object userId;

    @Note("客户端登录设备类型 ID")
    private String loginDeviceType;

    @Note("登录用户的类型标字符串标识（比如平台用户、小程序用户等等）")
    private String loginUserType;

    @Note("用户/账户的登录时间戳")
    private long loginTimeMill;

    @Note("token 具体过期的时间临界点")
    private long expirationMill;

    @Note("token 已经续期的次数")
    private int extendedCount;



    /* **************************************************************************************
     *
     *          构造器
     *
     * **************************************************************************************
     * */

    protected GenericAuthToken() {
        this.loginDeviceType = LoginDeviceType.BROWSER.getValue();
        this.loginUserType = "";
    }


    /* **************************************************************************************
     *
     *          Getter / Setter
     *
     * **************************************************************************************
     * */

    @Override
    public String getUuid() {
        return Objects.requireNonNull(uuid, "AuthToken 的 uuid 标识不能为空");
    }

    @Override
    public void setUuid(String uuid) {
        if(uuid != null && !uuid.isEmpty()) {
            this.uuid = uuid;
            return;
        }
        throw new IllegalArgumentException("不能设置空的 uuid 作为 AuthToken 的标识");
    }

    @Override
    public Object getUserId() {
        if(userId != null) {
            return userId;
        }
        throw new NullPointerException("userId 为 null");
    }

    @Override
    public String stringUserId() {
        return this.getUserId().toString();
    }

    @Override
    public long longUserId() {
        if(userId instanceof Long) {
            return (Long) userId;
        }
        if(userId instanceof String) {
            long id = Long.parseLong((String) userId);
            this.userId = id;
            return id;
        }
        long id = ((Integer) userId).longValue();
        this.userId = id;
        return id;
    }

    @Override
    public int intUserId() {
        if(userId instanceof Integer) {
            return (Integer) userId;
        }
        if(userId instanceof Long) {
            int id = ((Long) userId).intValue();
            this.userId = id;
            return id;
        }
        int id = Integer.parseInt((String) userId);
        this.userId = id;
        return id;
    }

    @Override
    public void setUserId(Object userId) {
        if(userId instanceof String || userId instanceof Long || userId instanceof Integer) {
            this.userId = userId;
            return;
        }
        throw new IllegalArgumentException("userId 仅支持字符串、int、long 类型");
    }

    @Override
    public void setUserId(String userId) {
        if(userId != null) {
            this.userId = userId;
            return;
        }
        throw new NullPointerException("userId 不能设置为 null");
    }

    @Override
    public void setUserId(long userId) {
        this.userId = userId;
    }

    @Override
    public void setUserId(int userId) {
        this.userId = userId;
    }

    @Override
    public String getLoginDeviceType() {
        return loginDeviceType;
    }

    @Override
    public void setLoginDeviceType(String loginDeviceType) {
        this.loginDeviceType = loginDeviceType;
    }

    @Override
    public void setLoginDeviceType(LoginDeviceType loginDeviceType) {
        if(loginDeviceType != null) {
            this.loginDeviceType = loginDeviceType.getValue();
            return;
        }
        throw new NullPointerException("不能设置 null 的设备类型");
    }

    @Override
    public String getLoginUserType() {
        return loginUserType;
    }

    @Override
    public void setLoginUserType(String loginUserType) {
        this.loginUserType = (loginUserType != null) ? loginUserType : "";
    }

    @Override
    public long getLoginTimeMill() {
        if(loginTimeMill > 0) {
            return loginTimeMill;
        }
        throw new InvalidDataException("用户登录时间应该是大于 0 的");
    }

    @Override
    public void setLoginTimeMill(long loginTime, Timeunit loginTimeunit) {
        if(loginTime > 0) {
            this.loginTimeMill = Timeunit.toMill(loginTime, loginTimeunit);
            return;
        }
        throw new IllegalArgumentException("用户登录时间应该是大于 0 的");
    }

    @Override
    public long getExpirationMill() {
        if(expirationMill > 0) {
            return expirationMill;
        }
        throw new InvalidDataException("AuthToken 的过期时间应该是大于 0 的");
    }

    @Override
    public void setExpirationMill(long expiration, Timeunit expirationTimeunit) {
        if(expiration > 0) {
            this.expirationMill = Timeunit.toMill(expiration, expirationTimeunit);;
            return;
        }
        throw new IllegalArgumentException("AuthToken 的过期时间应该是大于 0 的");
    }

    @Override
    public int getExtendedCount() {
        return extendedCount;
    }

    @Override
    public void setExtendedCount(int extendedCount) {
        this.extendedCount = extendedCount;
    }

    @Override
    public String toString() {
        return "uuid=" + uuid +
                ", userId=" + userId +
                ", loginDeviceType=" + loginDeviceType +
                ", loginUserType=" + loginUserType +
                ", loginTimeMill=" + loginTimeMill +
                ", expirationMill=" + expirationMill +
                ", extendedCount=" + extendedCount;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        GenericAuthToken authToken = (GenericAuthToken) o;
        if(!Objects.equals(userId, authToken.userId)) return false;
        if(!Objects.equals(loginDeviceType, authToken.loginDeviceType)) return false;
        if(!Objects.equals(loginUserType, authToken.loginUserType)) return false;
        return Objects.equals(uuid, authToken.uuid);
    }

    @Override
    public int hashCode() {
        return Objects.hash(uuid, userId, loginDeviceType, loginDeviceType);
    }


    /* **************************************************************************************
     *
     *          链式调用
     *
     * **************************************************************************************
     * */

    @Override
    public GenericAuthToken uuid(String uuid) {
        this.setUuid(uuid);
        return this;
    }

    @Override
    public GenericAuthToken userId(Object userId) {
        this.setUserId(userId);
        return this;
    }

    @Override
    public GenericAuthToken userId(String userId) {
        this.setUserId(userId);
        return this;
    }

    @Override
    public GenericAuthToken userId(long userId) {
        this.setUserId(userId);
        return this;
    }

    @Override
    public GenericAuthToken userId(int userId) {
        this.setUserId(userId);
        return this;
    }

    @Override
    public GenericAuthToken loginDeviceType(String loginDeviceType) {
        this.setLoginDeviceType(loginDeviceType);
        return this;
    }

    @Override
    public GenericAuthToken loginDeviceType(LoginDeviceType loginDeviceType) {
        this.setLoginDeviceType(loginDeviceType);
        return this;
    }

    @Override
    public GenericAuthToken loginUserType(String loginUserType) {
        this.setLoginUserType(loginUserType);
        return this;
    }

    @Override
    public GenericAuthToken loginTimeMill(long loginTime, Timeunit loginTimeunit) {
        this.setLoginTimeMill(loginTime, loginTimeunit);
        return this;
    }

    @Override
    public GenericAuthToken expirationMill(long expiration, Timeunit expirationTimeunit) {
        this.setExpirationMill(expiration, expirationTimeunit);
        return this;
    }

    @Override
    public GenericAuthToken extendedCount(int extendedCount) {
        this.setExtendedCount(extendedCount);
        return this;
    }


    /* **************************************************************************************
     *
     *          不对外开放的私有逻辑
     *
     * **************************************************************************************
     * */

    @Note("校验过期时间是否正常")
    protected void protected_checkExpiration() {
        long expiration = this.getExpirationMill();
        if(expiration <= System.currentTimeMillis()) {
            throw new DataGenerationException("AuthToken 设置的过期时间必须大于当前时间");
        }
    }
}
